﻿
package extremefx.ui {
	import extremefx.events.EventArgs;
	import extremefx.events.EventHandler;
	import extremefx.geom.Edge;
	import extremefx.geom.Size;
	import extremefx.modules.css.XTextFormat;
	import extremefx.ui.UIComponent;
	import extremefx.ui.styles.UIStates;
	import extremefx.ui.styles.UIStyle;
	
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;	

	/**
	 * @author Marcelo Volmaro
	 */
	public class Input extends UIComponent {
		private var _textF:TextField;
		private var _txtFmt:XTextFormat;
		private var _currentStyle:UIStyle;
		
		private var _caretIndex:int;
		private var _selStart:int;
		private var _selEnd:int;
		private var _listHooked:Boolean;
		
		private var _vScrollBar:VScrollBar;
		private var _hScrollBar:HScrollBar;
		private var _params:UIParameters;
		
		public function Input(pParameters:UIParameters = null, pMultiline:Boolean = false, pWordWrap:Boolean = false) {
			super();
			_focusVisual = false;
			
			_params = initStyle("Input", pParameters);
			_params._parent = this;

			var tf:TextField = _textF = new TextField();
			tf.autoSize = TextFieldAutoSize.NONE;
			tf.selectable = true;
			tf.type = TextFieldType.INPUT;
			tf.alwaysShowSelection = tf.tabEnabled = false;
			
			tf.addEventListener(FocusEvent.FOCUS_IN, _myFocusIn, false, 0, true);
			tf.addEventListener(FocusEvent.FOCUS_OUT, _myFocusOut, false, 0, true);
			tf.addEventListener(Event.CHANGE, _changeHandler, false, 0, true);
			
			tf.addEventListener(Event.SCROLL, _scrollHandler, false, 0, true);
			
			_mSprite.addChild(tf);
			
			var bd:BitmapData = _style.getFirstBMPData(); 
			
			_width = bd.width + _style.padding.left + _style.padding.right;
			_height = bd.height;
			
			tf.multiline = pMultiline;
			if (pMultiline) {
				_vScrollBar = new VScrollBar(_params);
				_vScrollBar.setKeyEnabled(false);
				_vScrollBar.focusable(false);
				_vScrollBar.onScroll.add(_onVScroll);
				_vScrollBar._componentSelect = function():void{
					_reFocus();
				};
				
				_mSprite.addChild(_vScrollBar._visualUI);
			}
			
			tf.wordWrap = pWordWrap;
			if (!pWordWrap && pMultiline){
				_hScrollBar = new HScrollBar(_params);
				_hScrollBar.setKeyEnabled(false);
				_hScrollBar.focusable(false);
				_hScrollBar.onScroll.add(_onHScroll);
				_hScrollBar._componentSelect = function():void{
					_reFocus();
				};
				
				_mSprite.addChild(_hScrollBar._visualUI);				
			}
		}

		private function _reFocus():void {
			if (UIStage.STAGE.focus == _textF) return;
			
			var hs:int = _textF.scrollH;
			var vs:int = _textF.scrollV;
			
			if (_visualUI.stage) _visualUI.stage.focus = _textF;
			_textF.setSelection(_selStart, _selEnd);
			_textF.scrollH = hs;
			_textF.scrollV = vs;
		}
		
		private function _updateData(pE:Event = null):void {
			var ci:int = _textF.caretIndex;
			if (-1 < ci){
				_caretIndex = ci;
				_selStart = _textF.selectionBeginIndex;
				_selEnd = _textF.selectionEndIndex;
			}
		}

		private function _myFocusIn(pE:FocusEvent):void {
			focus();
		}
		
		private function _myFocusOut(pE:FocusEvent):void {
			blur();
		}
		
		private function _changeHandler(pE:Event):void {
			if (_vScrollBar){
				_vScrollBar.setScrollProperties(_textF.bottomScrollV, 1, _textF.maxScrollV);
			}
			
			if (_hScrollBar){
				_hScrollBar.setScrollProperties(_textF.width, 0, _textF.maxScrollH);
			}
			
			_updateData();
			
			if (_eOnChange) _eOnChange.fire();
		}
		
		override public function focus():void {
			super.focus();
			if (_tabfocused){
				_textF.setSelection(0, _textF.text.length);
				
			} else {
				_reFocus();
			}
			
			if (!_listHooked){
				UIStage.addEventListener(KeyboardEvent.KEY_UP, _updateData);
				UIStage.addEventListener(MouseEvent.MOUSE_DOWN, _updateData);
			}
			
			_setView();
		}
		
		override public function blur():void {
			super.blur();
			_setView();
			
			if (_listHooked){
				UIStage.removeEventListener(KeyboardEvent.KEY_UP, _updateData);
				UIStage.removeEventListener(MouseEvent.MOUSE_DOWN, _updateData);
			}
		}
		
		private function _setView(pState:uint = UIStates.NORMAL):void{
			pState = _getState(pState, _focused);
			
			var tf:TextField = _textF,
			pad:Edge = _style.padding;
			_currentStyle = _style.getPseudoStyle(pState);
			(_txtFmt = _currentStyle.textFormat).applyToTextfield(tf);
			
			tf.x = pad.left + _currentStyle.position.left;
			tf.y = pad.top + _currentStyle.position.top;
			
			_setDecoState(pState, _width, _height);
		}
		
		override public function dispose():void {
			if (_disposing) return;
			super.dispose();
			
			_textF.removeEventListener(FocusEvent.FOCUS_IN, _myFocusIn);
			_textF.removeEventListener(FocusEvent.FOCUS_OUT, _myFocusOut);
			_textF.removeEventListener(Event.CHANGE, _changeHandler);
			_textF.removeEventListener(Event.SCROLL, _scrollHandler);
			
			if (_eOnChange) _eOnChange.dispose();
		}
		
		private function _scrollHandler(pE:Event):void {
			if (_vScrollBar){
				_vScrollBar.scrollPosition = _textF.scrollV;
			}
			
			if (_hScrollBar){
				_hScrollBar.scrollPosition = _textF.scrollH;
			}
		}

		override protected function _draw():void {
			var tf:TextField = _textF,
			pad:Edge = _style.padding,
			tfw:uint = _width - (pad.left + pad.right),
			h:uint = _height,
			tfh:uint,
			hsbw:uint = _width;

			if (tf.multiline){
				tfh = h - (pad.top + pad.bottom);
				
			} else {
				_height = (tfh = (_txtFmt.size as int) + 8) + (pad.top + pad.bottom);
			}
			
			if (_vScrollBar){
				var vsbw:uint = _vScrollBar.width;
				var vsbp:Edge = _vScrollBar.computedStyle.position;
				hsbw -= vsbw + vsbp.right;
				
				_vScrollBar.position = new Point(hsbw, vsbp.top);
				_vScrollBar.size = new Size(0, _height - vsbp.top - vsbp.bottom);
				tfw -= vsbw;
			}
			
			if (_hScrollBar){
				var hsbp:Edge = _hScrollBar.computedStyle.position;
				_hScrollBar.position = new Point(hsbp.left, _height - _hScrollBar.height - hsbp.bottom);
				_hScrollBar.size = new Size(hsbw - hsbp.left, 0);
				tfh -= _hScrollBar.height;
			}
			
			tf.width = tfw;
			tf.height = tfh;
			
			_setView();
		}
		
		override public function set enabled(pEnabled:Boolean):void {
			_textF.type = pEnabled ? TextFieldType.INPUT : TextFieldType.DYNAMIC;
			_textF.selectable = pEnabled;
			
			super.enabled = pEnabled;
		}
		
		public function get value():String {
			return _textF.text;
		}
		
		public function set value(pValue:String):void {
			_textF.text = pValue;
		}
		
		private function _onVScroll(pSender:VScrollBar, pArgs:EventArgs):void {
			_textF.scrollV = pSender.scrollPosition;
			_reFocus();
		}
		
		private function _onHScroll(pSender:HScrollBar, pArgs:EventArgs):void {
			_textF.scrollH = pSender.scrollPosition;
			_reFocus();
		}

		public function get password():Boolean {
			return _textF.displayAsPassword ;
		}
		
		public function set password(pPassword:Boolean):void {
			_textF.displayAsPassword = pPassword;
		}
		
		public function get restrict():String {
			return _textF.restrict;
		}
		
		public function set restrict(pRestrict:String):void {
			_textF.restrict = pRestrict;
		}
		
		private var _eOnChange:EventHandler;
		public function get onChange():EventHandler{
			if (_eOnChange == null) _eOnChange = new EventHandler(this);
			return _eOnChange;
		}
	}
}
